// gamemonkey.cpp : contains functions to expose and deal with all GameMonkey interaction
//$Id: GameMonkey.cpp 21 2009-08-17 05:31:44Z brwarner2 $

#include "stdafx.h"
#include "gamemonkey.h"
#include "ObjectManager.h"
#include "Components.h"

int GM_CDECL gmComponent( gmThread* );
int GM_CDECL gmHook( gmThread* );
int GM_CDECL gmGetObjectTable( gmThread* );

//Exposes functions that are used in object declarations
void ExposeObjectDeclarators( gmMachine& gm, gmTableObject* pTable )
{
	//Add the component function
	pTable->Set(&gm, "COMPONENT", gmVariable(gm.AllocFunctionObject(gmComponent)));

	//Add the "hook" function
	pTable->Set(&gm, "HOOK", gmVariable(gm.AllocFunctionObject(gmHook)));
}

//Hides the functions exposed by ExposeObjectDeclarators
void HideObjectDeclarators( gmMachine& gm, gmTableObject* pTable )
{
	//Remove component function
	pTable->Set(&gm, "COMPONENT", gmVariable::s_null);

	//Remove the hook function
	pTable->Set(&gm, "HOOK", gmVariable::s_null);

	//Clean up
	gm.CollectGarbage(true);
}

//Registers all of the GM functions that are used globally
void RegisterGlobalGM( gmMachine& gm )
{
	//Register get table function
	gm.RegisterLibraryFunction("GetObjectTable", gmGetObjectTable);

	//Register component IDs
	RegisterComponentIDs(gm);
}

//Used to place a component entry in an objects component table
int GM_CDECL gmComponent( gmThread* a_thread )
{
	//Get parameters
	GM_CHECK_NUM_PARAMS(1);
	GM_CHECK_INT_PARAM( id, 0 );

	//Get the table
	gmTableObject* me = a_thread->GetThis()->GetTableObjectSafe();
	if(!me) return GM_EXCEPTION;

	//Get the component list
	gmTableObject *comps = me->Get(a_thread->GetMachine(), "components").GetTableObjectSafe();
	if(!comps) return GM_EXCEPTION;

	//Add component ID
	comps->Set( a_thread->GetMachine(), gmVariable(comps->Count()), gmVariable(id) );
	return GM_OK;
}

//Used to add a hook to an object
int GM_CDECL gmHook( gmThread* a_thread )
{
	//Get parameters
	GM_CHECK_NUM_PARAMS(2);
	GM_CHECK_STRING_PARAM( hookname, 0 );
	GM_CHECK_FUNCTION_PARAM( hookfunc, 1 );

	//Get the machine
	gmMachine* pGM = a_thread->GetMachine();

	//Get the table
	gmTableObject* me = a_thread->GetThis()->GetTableObjectSafe();
	if(!me) return GM_EXCEPTION;

	//Get the hooks table
	gmTableObject *hooks = me->Get(pGM, "hooks").GetTableObjectSafe();
	if(!hooks) return GM_EXCEPTION;

	//Check if the hook list of this type exists, if not create it
	gmVariable hooklist = hooks->Get(pGM, hookname);
	if( hooklist.IsNull() ) 
		hooks->Set(pGM, hookname, gmVariable(pGM->AllocTableObject()));
	hooklist = hooks->Get(pGM, hookname);

	//Get the hook list table
	gmTableObject* hooklisttable = hooklist.GetTableObjectSafe();
	if(hooklisttable == 0) return GM_EXCEPTION;

	//Add the hook to the table
	unsigned int index = hooklisttable->Count();
	hooklisttable->Set( pGM, index, gmVariable(hookfunc) );
	return GM_OK;
}

//The "object manager" type
gmType ObjectManagerType = -1;

//Sets the global object manager in GM
void SetGlobalObjectManager( gmMachine& gm, CObjectManager* pObj )
{
	//If it has not already, register the object manager type
	if(ObjectManagerType == -1)
		ObjectManagerType = gm.CreateUserType("ObjectManagerType");

	//Set the global object manger object
	gm.GetGlobals()->Set(&gm, "OBJMAN", gmVariable( gm.AllocUserObject((void*)pObj, ObjectManagerType) ));
}

//Gets the global object manager from GM
CObjectManager* GetGlobalObjectManager( gmMachine& gm )
{
	return reinterpret_cast<CObjectManager*>(gm.GetGlobals()->Get(&gm, "OBJMAN").GetUserSafe(ObjectManagerType));
}

int GM_CDECL gmGetObjectTable( gmThread* a_thread )
{
	GM_CHECK_NUM_PARAMS(1);
	GM_CHECK_STRING_PARAM( name, 0 );
	gmMachine* pGM = a_thread->GetMachine();
	CObjectManager* pOM = GetGlobalObjectManager(*pGM);

	gmTableObject* table = pOM->GetObjectTable(name);
	a_thread->PushTable(table->Duplicate(pGM));
	return GM_OK;
}

//Prints error log
void PrintErrorLog( gmMachine& gm )
{
	gmLog &log = gm.GetLog();
	
	bool firstError = true;
	const char* err = log.GetEntry(firstError);
	while(err)
	{
		printf("Compilation error - %s \n", err);
		err = log.GetEntry(firstError);
	}
}